home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / DELIVER.PAK / DELIVER.CPP next >
C/C++ Source or Header  |  1997-05-06  |  17KB  |  779 lines

  1. ///////////////////////////////////////////////////////////////
  2. // IDE Demo Program                                          //
  3. // Delivery.cpp                                              //
  4. // Copyright (c) 1993 by Borland International               //
  5. ///////////////////////////////////////////////////////////////
  6. #include <stdio.h>
  7. #include <dir.h>
  8. #include <classlib\arrays.h>
  9. #include <cstring.h>
  10. #include <fstream.h>
  11.  
  12.  
  13. //                                                  //
  14. //  To take advantage of the tracing, attach the    //
  15. //  'Diagnostics' StyleSheet to this node by        //
  16. //  selecting 'Edit node attributes' from the       //
  17. //  node's SpeedMenu and selecting it from the      //
  18. //  StyleSheets dropdown                            //
  19. //                                                  //
  20.  
  21. DIAG_DEFINE_GROUP( IdeDeliver, 1, 1 );
  22.     
  23.  
  24. //                                                          //
  25. //  class Delivery                                          //
  26. //                                                          //
  27. //  class Delivery for reading command line and executing   //
  28. //  appropriate actions. If you wish to extend the          //
  29. //  functionality of this program, add a method to the      //
  30. //  to the Delivery class with the same prototype as        //
  31. //  Delivery::Copy and a corresponding entry to the static  //
  32. //  data member Delivery::_commands[]                       //
  33. //                                                          //
  34.  
  35. class Arguments;
  36.  
  37. class Delivery
  38. {
  39. public:
  40.  
  41.     //        Parser/Dispatcher        //
  42.     
  43.     void Execute( Arguments & );
  44.  
  45. protected:
  46.  
  47.     //        Commands        //
  48.     
  49.     void Copy   ( Arguments & );
  50.     void Move   ( Arguments & );
  51.     void MkDir  ( Arguments & );
  52.     void Clean  ( Arguments & );
  53.     void Rename ( Arguments & );
  54.  
  55.  
  56. private:
  57.  
  58.     //  Array of command methods and there text equivalents  //
  59.     
  60.     typedef void (Delivery::*commandMethod)( Arguments & );
  61.     
  62.     struct Commands
  63.     {
  64.         commandMethod    parser;
  65.         const char *cmdName;
  66.     };
  67.  
  68.     static Commands _commands[];
  69.  
  70.     // low-level helpers..    //
  71.  
  72.     enum FileCmd 
  73.     {
  74.         fcCopy,
  75.         fcMove
  76.     };
  77.     
  78.     void FilesCopyMove( Arguments &, FileCmd );
  79.     void FilesCopyMove( const char *, const char *, FileCmd );
  80.  
  81.     void FileCopy  ( const char *, const char *);
  82.     void FileMove  ( const char *, const char *, int );
  83.     void FileRename( const char *, const char *);
  84.     void FileDelete( const char *, int okToFail = 1 );
  85.     
  86. };
  87.  
  88.  
  89. //                                              //
  90. //    class Arguments                           //
  91. //    Array for holding command line arguments  //
  92. //                                              //
  93.  
  94. class _BIDSCLASS Arguments : public TArray<string>
  95. {
  96. public:
  97.     Arguments( int argc, char * * argv );
  98.  
  99.     //        Return the Deliver command text found on command line  //
  100.     
  101.     const char * command();
  102.  
  103.     //        Return the last filename on the command line. (This has  //
  104.     //        the side-effect of limiting the number of valid source   //
  105.     //        filenames by one.)                                       //
  106.     
  107.     const char * destination();
  108.  
  109.     //        Return the filename at 'index'. Valid values for index     //
  110.     //        start at 1 (one) and this method will return 0 when there  //
  111.     //        are no more source filenames.                              //
  112.     
  113.     const char * source( int index );
  114.     
  115. private:
  116.     
  117.     void expandFile( char * );
  118.     const char * arg(int i);
  119.  
  120.     int _destinationAt;
  121.     
  122. };
  123.  
  124. inline const char * 
  125. Arguments::arg( int i )
  126. {
  127.     return( ((*this)[i]).c_str() );
  128. }
  129.  
  130. //    PrintProgramSignature will output the program signature //
  131.  
  132. void PrintProgramSignature()
  133. {
  134.     static int headerHasBeenPut = 0;
  135.  
  136.     if( !headerHasBeenPut )
  137.     {
  138.         cout  << "Deliver:"
  139.                 << endl;
  140.                 
  141.         headerHasBeenPut = 1;
  142.     }
  143. }
  144.  
  145. //                 //
  146. //        main()   //
  147. //                 //
  148.  
  149. int main (int argc, char * argv[])
  150. {
  151.     int    returnCode;
  152.     
  153.     try
  154.     {
  155.         Arguments    args( argc, argv );
  156.  
  157.         Delivery        parser;
  158.  
  159.         parser.Execute( args );
  160.  
  161.         returnCode = 0;
  162.         
  163.     }
  164.     catch ( xmsg & x )
  165.     {  
  166.         PrintProgramSignature();
  167.         
  168.         cout    << "Fatal Error: " 
  169.                 << x.why() 
  170.                 << endl;
  171.                 
  172.         returnCode = 2;
  173.     }
  174.  
  175.     return returnCode;
  176.     
  177. }
  178.  
  179. //                                                  //
  180. //    class FileSpec for manipulation file paths    //
  181. //                                                  //
  182.  
  183. class FileSpec
  184. {
  185. public:
  186.     //        ctor        //
  187.     
  188.     FileSpec( const char * = "" );
  189.  
  190.     //        accessors            //
  191.     
  192.     const char *    path();
  193.     const char *    drive();
  194.     const char *    dir();
  195.     const char *    file();
  196.     const char *    ext();
  197.  
  198.     void            path(const char *);
  199.     void            drive(const char *);
  200.     void            dir(const char *);
  201.     void            file(const char *);
  202.     void            ext(const char *);
  203.     void            fileext( const char * );
  204.  
  205.     long            age();
  206.  
  207.     //        flags() returns FILENAME, WILDCARDS etc. flags found in dir.h  //
  208.     
  209.     int             flags();
  210.  
  211.     //        explicit splitter/merger    //
  212.     
  213.     int             split();
  214.     void            merge();
  215.  
  216.     //        disk manipulation and polling        //
  217.     
  218.     int             exists();
  219.     int             first();
  220.     int             next();
  221.  
  222.     //        Are this and another FileSpec referring to the same drive? //
  223.     
  224.     int             sameDrive( FileSpec & );
  225.  
  226.     //        Is this FileSpec really representing a directory?           //
  227.     
  228.     int             isDirectory();
  229.  
  230.     void            addTrailingSlash();
  231.     
  232.     //        Strip the trailing slash from the path() element and return  //
  233.     //        the path(). (Calling this invalidates the use dir(), file()  //
  234.     //        and ext()).                                                  //
  235.     
  236.     char *          stripTrailingSlash();
  237.         
  238. private:
  239.  
  240.     char _path [ MAXPATH  ];
  241.     char _drive[ MAXDRIVE ];
  242.     char _dir  [ MAXDIR   ];
  243.     char _file [ MAXFILE  ];
  244.     char _ext  [ MAXEXT   ];
  245.     int  _flags;
  246.  
  247.     struct ffblk    _dta;
  248. };     
  249.  
  250. inline
  251. FileSpec::FileSpec( const char * apath )
  252. {
  253.     path( apath );
  254. }
  255.  
  256. inline const char *  
  257. FileSpec::path()
  258. {
  259.     return( _path );
  260. }
  261.  
  262. inline const char *    
  263. FileSpec::drive()
  264. {
  265.     return( _drive );
  266. }
  267.  
  268. inline const char *    
  269. FileSpec::dir()
  270. {
  271.     return( _dir );
  272. }
  273.  
  274. inline const char *    
  275. FileSpec::file()
  276. {
  277.     return( _file );
  278. }
  279.  
  280. inline const char *    
  281. FileSpec::ext()
  282. {
  283.     return( _ext );
  284. }
  285.  
  286. inline int 
  287. FileSpec::flags()
  288. {
  289.     return( _flags );
  290. }
  291.  
  292. inline int
  293. FileSpec::exists()
  294. {
  295.     return( first() );
  296. }
  297.  
  298. inline long
  299. FileSpec::age()
  300. {
  301.     if( exists() )
  302.     {
  303.         unsigned long date = _dta.ff_fdate;
  304.         unsigned long time = _dta.ff_ftime;
  305.         
  306.         return( (long)( (date << 16) | time ) );
  307.     }
  308.     return( -1L );
  309. }
  310.  
  311. //                                  //
  312. //        class Delivery implemenation    //
  313. //                                  //
  314.  
  315. Delivery::Commands Delivery::_commands[] =
  316. {
  317.     { &Delivery::Copy,  "COPY"   },
  318.     { &Delivery::Move,  "MOVE"   },
  319.     { &Delivery::MkDir, "MKDIR"  },
  320.     { &Delivery::Clean, "CLEAN"  },
  321.     { &Delivery::Rename,"RENAME" },
  322.     { 0 }
  323. };
  324.  
  325. void 
  326. Delivery::Execute( Arguments & args )
  327. {
  328.     const char * cmdName = args.command();
  329.  
  330.     int cmdNo = -1;
  331.     
  332.     for( int i = 0; _commands[i].cmdName; i++ )
  333.     {
  334.         if( !stricmp( cmdName, _commands[i].cmdName ) )
  335.         {
  336.             cmdNo = i;
  337.             break;
  338.         }
  339.     }
  340.  
  341.     if( cmdNo == -1 )
  342.         throw xmsg( "Unknown command!" );
  343.  
  344.     (this->*_commands[cmdNo].parser)( args );
  345. }
  346.  
  347. void
  348. Delivery::FileCopy( const char * source, const char * destination )
  349. {
  350.     TRACEX( IdeDeliver, 0,
  351.                   "Copy source: \"" 
  352.                 << source 
  353.                 << "\" => \""
  354.                 << destination
  355.                 << "\"" );
  356.  
  357.     FILE    * in;
  358.     FILE  * out;
  359.  
  360.     if( (in = fopen(source, "rb")) == 0 )
  361.         throw xmsg( "Error opening source" );
  362.  
  363.     if( (out = fopen(destination, "wb")) == 0 )
  364.         throw xmsg( "Error opening destination" );
  365.  
  366.     register int c;
  367.  
  368.     while( (c = fgetc(in)) != EOF )
  369.         fputc(c,out);
  370.  
  371.     fclose(in);
  372.     fclose(out);
  373. }
  374.  
  375. void
  376. Delivery::FileMove
  377.     ( const char * source, const char * destination, int sameDrive )
  378. {
  379.     if( sameDrive )
  380.     {
  381.         //    '1' here means it's ok for Delete to fail...  //
  382.         
  383.         FileDelete( destination, 1 );
  384.         FileRename( source, destination );
  385.     }
  386.     else
  387.     {
  388.         FileCopy( source, destination );
  389.         FileDelete( source );
  390.     }
  391. }
  392.  
  393. void
  394. Delivery::FileDelete( const char * fileName, int okToFail )
  395. {
  396.     if( ::unlink( fileName ) && !okToFail )
  397.         throw xmsg( "Error deleting file" );
  398. }
  399.  
  400. void
  401. Delivery::FileRename( const char * oldName, const char * newName )
  402. {
  403.   if( ::rename( oldName, newName ) )
  404.         throw xmsg( "Error renaming file" );
  405. }
  406.  
  407. void
  408. Delivery::FilesCopyMove
  409.   ( const char * sourceFile, const char * destinationFile, FileCmd cmd )
  410. {
  411.     FileSpec    source     ( sourceFile );
  412.     FileSpec    destination( destinationFile );
  413.  
  414.     if( !source.first() )
  415.         throw    xmsg( "Can\'t find source" );
  416.  
  417.     int useSourceFileName;
  418.  
  419.     if( destination.isDirectory() )
  420.     {
  421.         destination.addTrailingSlash();    
  422.         useSourceFileName = 1;
  423.     }
  424.     else
  425.     {
  426.         useSourceFileName = 0;
  427.     }
  428.         
  429.     do
  430.     {
  431.         if( useSourceFileName )
  432.         {
  433.             destination.file( source.file() );
  434.             destination.ext ( source.ext()  );
  435.         }
  436.             
  437.         if( cmd == fcCopy )
  438.         {
  439.             //        Future: there could be a check here for the ages  //
  440.             //        of the FileSpecs if the user had requested        //
  441.             //        'update' copy                                     //
  442.             
  443.             FileCopy( source.path(), destination.path() );
  444.         }
  445.         else
  446.         {
  447.             FileMove(     source.path(), 
  448.                             destination.path(), 
  449.                             destination.sameDrive( source ) );
  450.         }
  451.  
  452.     } while( source.next() );
  453.     
  454. }
  455.     
  456.  
  457. void
  458. Delivery::FilesCopyMove( Arguments & args, FileCmd cmd )
  459. {
  460.     const char * destination = args.destination();
  461.  
  462.     const char * source;
  463.     
  464.     int i = 1;
  465.     
  466.     while( (source = args.source(i++)) != 0 )
  467.     {
  468.         FilesCopyMove( source, destination, cmd );
  469.     }
  470. }
  471.     
  472. void 
  473. Delivery::Copy ( Arguments & args )
  474. {
  475.     FilesCopyMove( args, fcCopy );
  476. }
  477.  
  478. void 
  479. Delivery::Move ( Arguments & args )
  480. {
  481.     FilesCopyMove( args, fcMove );
  482. }
  483.  
  484. void 
  485. Delivery::MkDir( Arguments & args )
  486. {
  487.     const char * source;
  488.     
  489.     int i = 1;
  490.  
  491.     while( (source = args.source(i++)) != 0 )
  492.     {
  493.         FileSpec    dirName( source );
  494.  
  495.         //    Future: it would be nice if this did a recursive   //
  496.         //    makedir like XCOPY                                 //
  497.         
  498.         if( ::mkdir( dirName.stripTrailingSlash() ) )
  499.             throw xmsg( "Error making directory" );
  500.     }
  501. }
  502.  
  503. void 
  504. Delivery::Clean( Arguments & args )
  505. {
  506.     const char * sourceFile;
  507.     FileSpec         source;
  508.     
  509.     int i = 1;
  510.     
  511.     while( (sourceFile = args.source(i++)) != 0 )
  512.     {
  513.         source.path( sourceFile );
  514.  
  515.         if( !source.exists() )
  516.         {
  517.             PrintProgramSignature();
  518.             cout    << "Warning DELIVER : Can\'t find "
  519.                     << source.path()
  520.                     << endl;
  521.             continue;
  522.         }
  523.         
  524.         do FileDelete( source.path() );
  525.           while( source.next() );
  526.     }
  527. }
  528.  
  529. void 
  530. Delivery::Rename( Arguments & args )
  531. {
  532.     if( args.GetItemsInContainer() != 3 )
  533.         throw    xmsg( "Wrong number of arguments for renaming" );
  534.  
  535.     FileRename( args.source(1), args.destination() );
  536. }
  537.  
  538.  
  539. //                                      //
  540. //      class Arguments implementation  //
  541. //                                      //
  542.  
  543. Arguments::Arguments( int argc, char * * argv )
  544.     : TArray<string>( 10 )
  545. {
  546.     for( int i = 1; i < argc; i++ )
  547.     {
  548.         char * arg = argv[i];
  549.  
  550.         if( *arg == '+' )
  551.             expandFile( arg+1 ); 
  552.         else
  553.             Add( arg );
  554.      }
  555.  
  556.     //        Initialize to one past the last item on the command line, if   //
  557.     //        the caller calls the destination() method, we'll crank this    //
  558.     //        back by one.                                                   //
  559.     
  560.     _destinationAt = GetItemsInContainer();
  561.      
  562. }
  563.     
  564.  
  565. void 
  566. Arguments::expandFile( char * fileName )
  567. {
  568.     //        This method will open a response file and treat every text  //
  569.     //        word found in the file as an entry on the command line      //
  570.     
  571.     ifstream    in( fileName );
  572.  
  573.     if( !in.good() )
  574.         throw    xmsg( "Can't open response file" );
  575.         
  576.     string    nextString;
  577.     
  578.     while( in.good() )
  579.     {
  580.         in >> nextString;
  581.         nextString.strip( string::Both, ' ' );
  582.         if( nextString.length() )
  583.             Add( nextString );
  584.     }
  585. }
  586.  
  587. const char *
  588. Arguments::source( int index )
  589. {
  590.     if( index < 1 )
  591.         throw xmsg( "Missing source operand" );
  592.         
  593.     return( index >= _destinationAt ? 0 : arg(index) );
  594. }
  595.  
  596. const char *
  597. Arguments::command()
  598. {
  599.     if( !GetItemsInContainer() )
  600.         throw xmsg( "Missing command" );
  601.         
  602.     return( arg(0) );
  603. }
  604.  
  605. const char * 
  606. Arguments::destination()
  607. {
  608.     if( GetItemsInContainer() < 3 )
  609.         throw xmsg( "Missing destination operand" );
  610.  
  611.     //    This controls the effictiveness of the method source()  //
  612.     
  613.     --_destinationAt;
  614.     
  615.     return( arg(_destinationAt) );
  616. }
  617.  
  618. //                                 //
  619. //    class FileSpec implementation   //
  620. //                                 //
  621.  
  622. int 
  623. FileSpec::split()
  624. {
  625.     return( _flags = ::fnsplit( _path, _drive, _dir, _file, _ext ) );
  626. }
  627.  
  628. void 
  629. FileSpec::merge()
  630. {
  631.     ::fnmerge( _path, _drive, _dir, _file, _ext );
  632. }
  633.  
  634. void 
  635. FileSpec::path(const char *path)
  636. {
  637.     strcpy( _path, path );
  638.     split();
  639. }
  640.  
  641. void 
  642. FileSpec::drive(const char *drive)
  643. {
  644.     strcpy( _drive, drive );
  645.     merge();
  646. }
  647.  
  648. void 
  649. FileSpec::dir(const char *dir)
  650. {
  651.     strcpy( _dir, dir );
  652.     merge();
  653. }
  654.  
  655. void 
  656. FileSpec::file(const char *file)
  657. {
  658.     strcpy( _file, file );
  659.     merge();
  660. }
  661.  
  662. void 
  663. FileSpec::ext(const char *ext)
  664. {
  665.     strcpy( _ext, ext );
  666.     merge();
  667. }
  668.  
  669. void
  670. FileSpec::fileext( const char *fileExt )
  671. {
  672.     char * p = (char *)(strchr(fileExt,'.'));
  673.  
  674.     if( !p )
  675.         p = "";
  676.  
  677.     ext( p );
  678.     *p = 0;
  679.  
  680.     file( fileExt );
  681. }
  682.  
  683. int 
  684. FileSpec::first()
  685. {
  686.     if( ::findfirst( _path, &_dta, 0 ) == -1 )    
  687.         return(0);
  688.  
  689.     fileext( _dta.ff_name );
  690.     return( 1 );
  691. }
  692.  
  693. int
  694. FileSpec::next()
  695. {
  696.     if( ::findnext( &_dta ) == -1 )
  697.         return( 0 );
  698.  
  699.     fileext( _dta.ff_name );
  700.     return( 1 );
  701. }
  702.  
  703. int
  704. FileSpec::sameDrive( FileSpec & other )
  705. {
  706.     if( *_drive == *other._drive )
  707.         return(1);
  708.  
  709.     if( !*_drive )
  710.     {
  711.         _drive[0] = ::getdisk() + 'A' - 1;
  712.         _drive[1] = ':';
  713.         _drive[2] = 0;
  714.     }
  715.     else
  716.     {
  717.         if( !*other._drive )
  718.         {
  719.             other._drive[0] = ::getdisk() + 'A' - 1;
  720.             other._drive[1] = ':';
  721.             other._drive[2] = 0;
  722.         }
  723.     }
  724.  
  725.     char    s[3];
  726.  
  727.     s[0] = *_drive;
  728.     s[1] = *other._drive;
  729.     s[2] = 0;
  730.     
  731.     strlwr( s );
  732.  
  733.     return( s[0] == s[1] );
  734. }
  735.  
  736. int
  737. FileSpec::isDirectory()
  738. {
  739.     int lastCharPos = strlen( _path ) - 1;
  740.  
  741.     char lastChar;
  742.     
  743.     if(((lastChar = _path[lastCharPos]) == '\\') || (lastChar == '/'))
  744.         _path[lastCharPos] = 0;
  745.  
  746.     int ret =  (::findfirst( _path, &_dta, FA_DIREC ) != -1 ) &&
  747.                   ( _dta.ff_attrib & FA_DIREC );
  748.              
  749.     _path[ lastCharPos ] = lastChar;
  750.         
  751.     return( ret );
  752. }
  753.  
  754. char *
  755. FileSpec::stripTrailingSlash()
  756. {
  757.     int lastCharPos = strlen( _path ) - 1;
  758.  
  759.     if( (_path[lastCharPos] == '\\') || (_path[lastCharPos] == '/') )
  760.         _path[lastCharPos] = 0;
  761.  
  762.     return( _path );
  763. }
  764.  
  765. void
  766. FileSpec::addTrailingSlash()
  767. {
  768.     int lastCharPos = strlen( _path ) - 1;
  769.  
  770.     if( (_path[lastCharPos] != '\\') && (_path[lastCharPos] != '/') )
  771.     {
  772.         strcat( _path, "\\" );
  773.         split();
  774.     }
  775. }
  776.     
  777.  
  778. //  End of file     //
  779.